<?php

abstract class RSCharacterRecord implements ArrayAccess
{
	private $owner;
	private $properties;
	protected $values;

	public function __construct (& $values, $owner, $properties)
	{
		foreach ($properties as $key => $call)
		{
			if (!isset($values[$key]))
			{
				throw new RecordPropertyException("Missing record property '$key'");
			}

			$this->properties[$key] = $call;
			$this->values[$key] = & $values[$key];
		}

		$this->owner = $owner;
	}

	public function getCharacter ()
	{
		if (is_string($this->owner))
		{
			return new RSCharacter($this->owner);
		}
		elseif ($this->owner instanceof RSCharacter)
		{
			return $this->owner;
		}

		throw new RSHiLibRuntimeException("Unexpected record owner type");
	}

	public function getName ()
	{
		if (is_string($this->owner))
		{
			return rshl_get_formatted_name($this->owner);
		}
		elseif ($this->owner instanceof RSCharacter)
		{
			return (string) $this->owner;
		}

		throw new RSHiLibRuntimeException("Unexpected record owner type");
	}

	public function __set ($name, $value)
	{
		$name = $this->verifyPropertyName($name);
		$this->{'set' . $this->properties[$name]}($value);
	}

	public function __get ($name)
	{
		$name = $this->verifyPropertyName($name);
		$this->{'get' . $this->properties[$name]}($value);
	}

	public function __isset ($name)
	{
		try
		{
			$this->verifyPropertyName($name);
		}
		catch (RecordPropertyException $ex)
		{
			return false;
		}

		return true;
	}

	public function __unset ($name)
	{
		throw new RecordPropertyException("Can no unset record properties");
	}

	private function verifyPropertyName ($name)
	{
		if (!isset($this->properties[$name]))
		{
			throw new RecordPropertyException("Unknown record property '$name'");
		}

		return $name;
	}

	public function offsetExists ($offset)
	{
		return $this->__isset($offset);
	}

	public function offsetGet ($offset)
	{
		return $this->__get($offset);
	}

	public function offsetSet ($offset, $value)
	{
		$this->__set($offset, $value);
	}

	public function offsetUnset ($offset)
	{
		$this->__unset($offset);
	}

	public abstract function __toString ();
}
